package com.shareppy.norman.sqlite.em;

import java.util.List;
import java.util.Map;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.shareppy.norman.core.annotations.Entity;
import com.shareppy.norman.core.db.CursorWrapper;
import com.shareppy.norman.core.em.EntityManager;
import com.shareppy.norman.core.entity.AbstractEntity;
import com.shareppy.norman.core.queries.ComplexQuery;
import com.shareppy.norman.core.sql.QueryBuilder;
import com.shareppy.norman.core.util.EntityUtils;
import com.shareppy.norman.sqlite.db.SQLiteConnection;
import com.shareppy.norman.sqlite.db.SQLiteCursor;
import com.shareppy.norman.util.MapToContentValuesConverter;
import com.shareppy.utils.CollectionsUtil;
import com.shareppy.utils.ReflectionUtils;

public class SQLiteEntityManager implements EntityManager {

	private SQLiteConnection dbconnection;
	public static int oConnections = 0;

	public SQLiteEntityManager(SQLiteConnection dbconnection) {
		this.dbconnection = dbconnection;
	}

	@Override
	public void release() {
		if (dbconnection != null) {
			((SQLiteDatabase) dbconnection.raw()).close();
			oConnections--;
			// System.out.println("Conexiones abiertas(-): "+AndroidEntityManager.oConnections);
		}
	}

	@Override
	public <T extends AbstractEntity> T save(T entity) throws Exception {
		ReflectionUtils.checkAnnotation(entity, Entity.class);
		SQLiteDatabase _db = (SQLiteDatabase) dbconnection.raw();
		Map<String, Object> contentValuesMap = EntityUtils
				.getContentValues(entity);
		ContentValues contentValues = new MapToContentValuesConverter()
				.convert(contentValuesMap);
		if (EntityUtils.isCreate(entity)) {
			// ITrigger<T> trigger = getTrigger(entity);
			// trigger.before(entity);
			long newId = _db.insertOrThrow(entity.getTableName(), null,
					contentValues);
			entity.setId(newId);
			// trigger.after(entity);
		} else {
			_db.update(entity.getTableName(), contentValues,
					AbstractEntity.ID_COLUMN.concat(" = ?"),
					new String[] { String.valueOf(entity.getId()) });
		}
		return entity;
	}

	// @SuppressWarnings("unchecked")
	// private <T extends AbstractEntity> ITrigger<T> getTrigger(T entity)
	// throws InstantiationException, IllegalAccessException {
	// Trigger trigger = entity.getClass().getAnnotation(Trigger.class);
	// if (trigger == null || trigger.value() == null) {
	// return new ITrigger<T>() {
	// @Override
	// public void before(T entity) throws Exception {
	// System.out.println("Before: " + entity);
	// }
	//
	// @Override
	// public void after(T entity) throws Exception {
	// System.out.println("After: " + entity);
	// }
	// };
	// }
	// return (ITrigger<T>) trigger.value().newInstance();
	// }

	// @Override
	// public <T extends AbstractEntity> List<T> query(T entity, String
	// queryName)
	// throws Exception {
	// if (queryName == null) {
	// return query( //
	// dbconnection,//
	// entity,//
	// entity.getTableName(),//
	// EntityUtil.getColumnArray(null, entity),//
	// null,//
	// null, //
	// null, //
	// null, //
	// null//
	// );
	// }
	//
	// Query query = entity.getClass().getAnnotation(Query.class);
	// if (query != null) {
	// if (queryName.equals(query.name())) {
	// String selection = EntityUtil.parseConditions(query
	// .conditions());
	// String[] params = EntityUtil.getConditionParams(entity,
	// query.conditions());
	// return query( //
	// dbconnection,//
	// entity,//
	// entity.getTableName(),//
	// EntityUtil.getColumnArray(query.columns(), entity),//
	// selection,//
	// params, //
	// EntityUtil.getGroupByClause(query.groupBy()), //
	// null, //
	// null//
	// );
	// }
	// }
	//
	// Queries queries = entity.getClass().getAnnotation(Queries.class);
	// if (queries != null) {
	// Query[] values = queries.value();
	// for (Query _query : values) {
	// if (queryName.equals(_query.name())) {
	// String selection = EntityUtil.parseConditions(_query
	// .conditions());
	// String[] params = EntityUtil.getConditionParams(entity,
	// _query.conditions());
	// return query(
	// //
	// dbconnection,//
	// entity,//
	// entity.getTableName(),//
	// EntityUtil.getColumnArray(_query.columns(), entity),//
	// selection,//
	// params, //
	// EntityUtil.getGroupByClause(_query.groupBy()), //
	// null, //
	// null//
	// );
	// }
	// }
	// }
	// return null;
	// }
	//
	// private <DB extends DBConnection, T extends AbstractEntity> List<T>
	// query(//
	// DB db,//
	// T entity, //
	// String tableName, //
	// String[] columns,//
	// String selection, //
	// String[] params, //
	// String groupBy, //
	// String having,//
	// String orderBy//
	// ) throws Exception {
	// Cursor cursor = ((SQLiteDatabase) db.raw()).query(//
	// tableName,//
	// columns, //
	// selection,//
	// params, //
	// groupBy, //
	// having, //
	// orderBy//
	// );
	// return EntityUtil.cursorToList(entity, columns, cursor);
	// }

	@Override
	public <E extends AbstractEntity, R> CursorWrapper<?> raw_query(
			ComplexQuery<E, R> complexQuery) throws Exception {
		SQLiteDatabase _db = ((SQLiteDatabase) dbconnection.raw());
		QueryBuilder query = complexQuery.getQuery();
		Cursor cursor = _db.rawQuery(query.toString(),
				CollectionsUtil.toStringArray(complexQuery.getParameters()));
		return new SQLiteCursor(cursor);
	}

	@Override
	public <T extends AbstractEntity, R> R query(ComplexQuery<T, R> complexQuery)
			throws Exception {
		SQLiteDatabase _db = ((SQLiteDatabase) dbconnection.raw());
		QueryBuilder query = complexQuery.getQuery();
		Cursor cursor = _db.rawQuery(query.toString(),
				CollectionsUtil.toStringArray(complexQuery.getParameters()));
		R result = complexQuery.transform(new SQLiteCursor(cursor));
		if (!cursor.isClosed()) {
			cursor.close();
		}
		return result;
	}

	@Override
	public <E extends AbstractEntity> E delete(E entity) throws Exception {
		SQLiteDatabase _db = ((SQLiteDatabase) dbconnection.raw());
		_db.beginTransaction();
		_db.execSQL("DELETE FROM " + EntityUtils.getTableName(entity)
				+ " WHERE " + AbstractEntity.ID_COLUMN + "=?",
				new Object[] { entity.getId() });
		_db.endTransaction();
		return entity;
	}

	@Override
	public <E extends AbstractEntity> void delete(List<E> entityList)
			throws Exception {
		if (entityList == null || entityList.isEmpty()) {
			return;
		}
		List<Long> ids = EntityUtils.getIds(entityList);
		StringBuilder inQuestions = new StringBuilder();
		for (int i = 0; i < ids.size(); i++) {
			inQuestions.append(',').append('?');
		}
		SQLiteDatabase _db = ((SQLiteDatabase) dbconnection.raw());
		_db.execSQL(
				"DELETE FROM " + EntityUtils.getTableName(entityList.get(0))
						+ " WHERE " + AbstractEntity.ID_COLUMN + " in ("
						+ inQuestions.substring(1) + ")", ids.toArray());
	}
}
